<!-- TOC -->

- [4.1. Лексическая структура](#41-%d0%9b%d0%b5%d0%ba%d1%81%d0%b8%d1%87%d0%b5%d1%81%d0%ba%d0%b0%d1%8f-%d1%81%d1%82%d1%80%d1%83%d0%ba%d1%82%d1%83%d1%80%d0%b0)
  - [4.1.1. Идентификаторы и ключевые слова](#411-%d0%98%d0%b4%d0%b5%d0%bd%d1%82%d0%b8%d1%84%d0%b8%d0%ba%d0%b0%d1%82%d0%be%d1%80%d1%8b-%d0%b8-%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%b2%d1%8b%d0%b5-%d1%81%d0%bb%d0%be%d0%b2%d0%b0)
  - [4.1.2. Константы](#412-%d0%9a%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b)
    - [4.1.2.1. Строковые константы](#4121-%d0%a1%d1%82%d1%80%d0%be%d0%ba%d0%be%d0%b2%d1%8b%d0%b5-%d0%ba%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b)
    - [4.1.2.2. Строковые константы со спецпоследовательностями в стиле C](#4122-%d0%a1%d1%82%d1%80%d0%be%d0%ba%d0%be%d0%b2%d1%8b%d0%b5-%d0%ba%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b-%d1%81%d0%be-%d1%81%d0%bf%d0%b5%d1%86%d0%bf%d0%be%d1%81%d0%bb%d0%b5%d0%b4%d0%be%d0%b2%d0%b0%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d1%81%d1%82%d1%8f%d0%bc%d0%b8-%d0%b2-%d1%81%d1%82%d0%b8%d0%bb%d0%b5-c)
    - [4.1.2.3. Строковые константы со спецпоследовательностями Unicode](#4123-%d0%a1%d1%82%d1%80%d0%be%d0%ba%d0%be%d0%b2%d1%8b%d0%b5-%d0%ba%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b-%d1%81%d0%be-%d1%81%d0%bf%d0%b5%d1%86%d0%bf%d0%be%d1%81%d0%bb%d0%b5%d0%b4%d0%be%d0%b2%d0%b0%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d1%81%d1%82%d1%8f%d0%bc%d0%b8-unicode)
    - [4.1.2.4. Строковые константы, заключённые в доллары](#4124-%d0%a1%d1%82%d1%80%d0%be%d0%ba%d0%be%d0%b2%d1%8b%d0%b5-%d0%ba%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b-%d0%b7%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d1%91%d0%bd%d0%bd%d1%8b%d0%b5-%d0%b2-%d0%b4%d0%be%d0%bb%d0%bb%d0%b0%d1%80%d1%8b)
      - [4.1.2.5. Битовые строковые константы](#4125-%d0%91%d0%b8%d1%82%d0%be%d0%b2%d1%8b%d0%b5-%d1%81%d1%82%d1%80%d0%be%d0%ba%d0%be%d0%b2%d1%8b%d0%b5-%d0%ba%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b)
      - [4.1.2.6. Числовые константы](#4126-%d0%a7%d0%b8%d1%81%d0%bb%d0%be%d0%b2%d1%8b%d0%b5-%d0%ba%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b)
      - [4.1.2.7. Константы других типов](#4127-%d0%9a%d0%be%d0%bd%d1%81%d1%82%d0%b0%d0%bd%d1%82%d1%8b-%d0%b4%d1%80%d1%83%d0%b3%d0%b8%d1%85-%d1%82%d0%b8%d0%bf%d0%be%d0%b2)
  - [4.1.3. Операторы](#413-%d0%9e%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%be%d1%80%d1%8b)
  - [4.1.4. Специальные знаки](#414-%d0%a1%d0%bf%d0%b5%d1%86%d0%b8%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d0%b5-%d0%b7%d0%bd%d0%b0%d0%ba%d0%b8)
  - [4.1.5. Комментарии](#415-%d0%9a%d0%be%d0%bc%d0%bc%d0%b5%d0%bd%d1%82%d0%b0%d1%80%d0%b8%d0%b8)
  - [4.1.6. Приоритеты операторов](#416-%d0%9f%d1%80%d0%b8%d0%be%d1%80%d0%b8%d1%82%d0%b5%d1%82%d1%8b-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%be%d1%80%d0%be%d0%b2)
- [4.2. Выражения значения](#42-%d0%92%d1%8b%d1%80%d0%b0%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-%d0%b7%d0%bd%d0%b0%d1%87%d0%b5%d0%bd%d0%b8%d1%8f)
  - [4.2.1.  Ссылки на столбцы](#421-%d0%a1%d1%81%d1%8b%d0%bb%d0%ba%d0%b8-%d0%bd%d0%b0-%d1%81%d1%82%d0%be%d0%bb%d0%b1%d1%86%d1%8b)
  - [4.2.2.  Позиционные параметры](#422-%d0%9f%d0%be%d0%b7%d0%b8%d1%86%d0%b8%d0%be%d0%bd%d0%bd%d1%8b%d0%b5-%d0%bf%d0%b0%d1%80%d0%b0%d0%bc%d0%b5%d1%82%d1%80%d1%8b)
  - [4.2.3.  Индексы элементов](#423-%d0%98%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d1%8b-%d1%8d%d0%bb%d0%b5%d0%bc%d0%b5%d0%bd%d1%82%d0%be%d0%b2)
  - [4.2.4.  Выбор поля](#424-%d0%92%d1%8b%d0%b1%d0%be%d1%80-%d0%bf%d0%be%d0%bb%d1%8f)
  - [4.2.5.  Применение оператора](#425-%d0%9f%d1%80%d0%b8%d0%bc%d0%b5%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%be%d1%80%d0%b0)
  - [4.2.6.  Вызовы функций](#426-%d0%92%d1%8b%d0%b7%d0%be%d0%b2%d1%8b-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b9)
  - [4.2.7.  Агрегатные выражения](#427-%d0%90%d0%b3%d1%80%d0%b5%d0%b3%d0%b0%d1%82%d0%bd%d1%8b%d0%b5-%d0%b2%d1%8b%d1%80%d0%b0%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f)
    - [percentile_cont](#percentilecont)
    - [generate_series](#generateseries)
  - [4.2.8.  Вызовы оконных функций](#428-%d0%92%d1%8b%d0%b7%d0%be%d0%b2%d1%8b-%d0%be%d0%ba%d0%be%d0%bd%d0%bd%d1%8b%d1%85-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b9)
    - [форма вызова](#%d1%84%d0%be%d1%80%d0%bc%d0%b0-%d0%b2%d1%8b%d0%b7%d0%be%d0%b2%d0%b0)
    - [определение_окна](#%d0%be%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5%d0%be%d0%ba%d0%bd%d0%b0)
    - [определение_рамки](#%d0%be%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5%d1%80%d0%b0%d0%bc%d0%ba%d0%b8)
    - [начало_рамки и конец_рамки](#%d0%bd%d0%b0%d1%87%d0%b0%d0%bb%d0%be%d1%80%d0%b0%d0%bc%d0%ba%d0%b8-%d0%b8-%d0%ba%d0%be%d0%bd%d0%b5%d1%86%d1%80%d0%b0%d0%bc%d0%ba%d0%b8)
    - [исключение_рамки](#%d0%b8%d1%81%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5%d1%80%d0%b0%d0%bc%d0%ba%d0%b8)
    - [PARTITION BY](#partition-by)
    - [UNBOUNDED](#unbounded)
  - [4.2.9.  Приведения типов](#429-%d0%9f%d1%80%d0%b8%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d1%8f-%d1%82%d0%b8%d0%bf%d0%be%d0%b2)
    - [как вызов функции](#%d0%ba%d0%b0%d0%ba-%d0%b2%d1%8b%d0%b7%d0%be%d0%b2-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8)
  - [4.2.10.  Применение правил сортировки](#4210-%d0%9f%d1%80%d0%b8%d0%bc%d0%b5%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb-%d1%81%d0%be%d1%80%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%ba%d0%b8)
    - [COLLATE](#collate)
  - [4.2.11. Скалярные подзапросы](#4211-%d0%a1%d0%ba%d0%b0%d0%bb%d1%8f%d1%80%d0%bd%d1%8b%d0%b5-%d0%bf%d0%be%d0%b4%d0%b7%d0%b0%d0%bf%d1%80%d0%be%d1%81%d1%8b)
  - [4.2.12. Конструкторы массивов](#4212-%d0%9a%d0%be%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%ba%d1%82%d0%be%d1%80%d1%8b-%d0%bc%d0%b0%d1%81%d1%81%d0%b8%d0%b2%d0%be%d0%b2)
    - [array from create table](#array-from-create-table)
    - [empty array](#empty-array)
    - [crate as result of subquery](#crate-as-result-of-subquery)
      - [with generate_series](#with-generateseries)
  - [4.2.13. Конструкторы табличных строк](#4213-%d0%9a%d0%be%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%ba%d1%82%d0%be%d1%80%d1%8b-%d1%82%d0%b0%d0%b1%d0%bb%d0%b8%d1%87%d0%bd%d1%8b%d1%85-%d1%81%d1%82%d1%80%d0%be%d0%ba)
  - [4.2.14. Правила вычисления выражений](#4214-%d0%9f%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d0%b0-%d0%b2%d1%8b%d1%87%d0%b8%d1%81%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f-%d0%b2%d1%8b%d1%80%d0%b0%d0%b6%d0%b5%d0%bd%d0%b8%d0%b9)
- [4.3. Вызов функций](#43-%d0%92%d1%8b%d0%b7%d0%be%d0%b2-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b9)
  - [4.3.1. Позиционная передача](#431-%d0%9f%d0%be%d0%b7%d0%b8%d1%86%d0%b8%d0%be%d0%bd%d0%bd%d0%b0%d1%8f-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%87%d0%b0)
  - [4.3.2. Именная передача](#432-%d0%98%d0%bc%d0%b5%d0%bd%d0%bd%d0%b0%d1%8f-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%87%d0%b0)
  - [4.3.3. Смешанная передача](#433-%d0%a1%d0%bc%d0%b5%d1%88%d0%b0%d0%bd%d0%bd%d0%b0%d1%8f-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%87%d0%b0)

<!-- /TOC -->

<https://postgrespro.ru/docs/postgrespro/12/sql-syntax>

# [4.1. Лексическая структура](https://postgrespro.ru/docs/postgrespro/12/sql-syntax-lexical)

SQL-программа состоит из последовательности команд. Команда, в свою очередь, представляет собой последовательность компонентов, оканчивающуюся точкой с запятой («;»). Конец входного потока также считается концом команды. Какие именно компоненты допустимы для конкретной команды, зависит от её синтаксиса.

Компонентом команды может быть ключевое слово, идентификатор, идентификатор в кавычках, строка (или константа) или специальный символ. Компоненты обычно разделяются пробельными символами (пробел, табуляция, перевод строки), но это не требуется, если нет неоднозначности (например, когда спецсимвол оказывается рядом с компонентом другого типа).

Например, следующий текст является правильной (синтаксически) SQL-программой:

    SELECT * FROM MY_TABLE;
    UPDATE MY_TABLE SET A = 5;
    INSERT INTO MY_TABLE VALUES (3, 'hi there');
Это последовательность трёх команд, по одной в строке (хотя их можно было разместить и в одну строку или наоборот, разделить команды на несколько строк).

Кроме этого, SQL-программы могут содержать комментарии. Они не являются компонентами команд, а по сути равносильны пробельным символам.

Синтаксис SQL не очень строго определяет, какие компоненты идентифицируют команды, а какие — их операнды или параметры. Первые несколько компонентов обычно содержат имя команды, так что в данном примере мы можем говорить о командах «SELECT», «UPDATE» и «INSERT». Но например, команда UPDATE требует, чтобы также в определённом положении всегда стоял компонент SET, а INSERT в приведённом виде требует наличия компонента VALUES. Точные синтаксические правила для каждой команды описаны в Части VI.


## 4.1.1. Идентификаторы и ключевые слова

[SQL-SYNTAX-IDENTIFIERS.sql](tutorial-sql\sql-syntax\SQL-SYNTAX-IDENTIFIERS.sql)
content\tutorial-sql\sql-syntax\SQL-SYNTAX-IDENTIFIERS.sql
Показанные выше команды содержали компоненты SELECT, UPDATE и VALUES, которые являются примерами ключевых слов, то есть слов, имеющих фиксированное значение в языке SQL. Компоненты MY_TABLE и A являются примерами идентификаторов. Они идентифицируют имена таблиц, столбцов или других объектов баз данных, в зависимости от того, где они используются. Поэтому иногда их называют просто «именами». Ключевые слова и идентификаторы имеют одинаковую лексическую структуру, то есть, не зная языка, нельзя определить, является ли некоторый компонент ключевым словом или идентификатором. Полный список ключевых слов приведён в Приложении C.

Идентификаторы и ключевые слова SQL должны начинаться с буквы (a-z, хотя допускаются также не латинские буквы и буквы с диакритическими знаками) или подчёркивания (_). Последующими символами в идентификаторе или ключевом слове могут быть буквы, цифры (0-9), знаки доллара ($) или подчёркивания. Заметьте, что строго следуя букве стандарта SQL, знаки доллара нельзя использовать в идентификаторах, так что их использование вредит переносимости приложений. В стандарте SQL гарантированно не будет ключевых слов с цифрами и начинающихся или заканчивающихся подчёркиванием, так что идентификаторы такого вида защищены от возможных конфликтов с будущими расширениями стандарта.

Система выделяет для идентификатора не более NAMEDATALEN-1 байт, а более длинные имена усекаются. По умолчанию NAMEDATALEN равно 64, так что максимальная длина идентификатора равна 63 байтам. Если этого недостаточно, этот предел можно увеличить, изменив константу NAMEDATALEN в файле src/include/pg_config_manual.h.

Ключевые слова и идентификаторы без кавычек воспринимаются системой без учёта регистра. Таким образом:

    UPDATE MY_TABLE SET A = 5;
    равносильно записи:

    uPDaTE my_TabLE SeT a = 5;
Часто используется неформальное соглашение записывать ключевые слова заглавными буквами, а имена строчными, например:

    UPDATE my_table SET a = 5;
Есть и другой тип идентификаторов: отделённые идентификаторы или идентификаторы в кавычках. Они образуются при заключении обычного набора символов в двойные кавычки ("). Такие идентификаторы всегда будут считаться идентификаторами, но не ключевыми словами. Так "select" можно использовать для обозначения столбца или таблицы «select», тогда как select без кавычек будет воспринят как ключевое слово и приведёт к ошибке разбора команды в месте, где ожидается имя таблицы или столбца. Тот же пример можно переписать с идентификаторами в кавычках следующим образом:

    UPDATE "my_table" SET "a" = 5;
Идентификаторы в кавычках могут содержать любые символы, за исключением символа с кодом 0. (Чтобы включить в такой идентификатор кавычки, продублируйте их.) Это позволяет создавать таблицы и столбцы с именами, которые иначе были бы невозможны, например, с пробелами или амперсандами. Ограничение длины при этом сохраняется.

Ещё один вариант идентификаторов в кавычках позволяет использовать символы Unicode по их кодам. Такой идентификатор начинается с U& (строчная или заглавная U и амперсанд), а затем сразу без пробелов идёт двойная кавычка, например U&"foo". (Заметьте, что при этом возникает неоднозначность с оператором &. Чтобы её избежать, окружайте этот оператор пробелами.) Затем в кавычках можно записывать символы Unicode двумя способами: обратная косая черта, а за ней код символа из четырёх шестнадцатеричных цифр, либо обратная косая черта, знак плюс, а затем код из шести шестнадцатеричных цифр. Например, идентификатор "data" можно записать так:

    U&"d\0061t\+000061"
В следующем менее тривиальном примере закодировано русское слово «слон», записанное кириллицей:

    U&"\0441\043B\043E\043D"
Если вы хотите использовать не обратную косую черту, а другой спецсимвол, его можно указать, добавив UESCAPE после строки, например:

    U&"d!0061t!+000061" UESCAPE '!'
В качестве спецсимвола можно выбрать любой символ, кроме шестнадцатеричной цифры, знака плюс, апострофа, кавычки или пробельного символа. Заметьте, что спецсимвол заключается не в двойные кавычки, а в апострофы.

Чтобы сделать спецсимволом знак апострофа, напишите его дважды.

Unicode-формат полностью поддерживается только при использовании на сервере кодировки UTF8. Когда используются другие кодировки, допускается указание только ASCII-символов (с кодами до \007F). И в четырёх, и в шестизначной форме можно записывать суррогатные пары UTF-16 и таким образом составлять символы с кодами больше чем U+FFFF, хотя наличие шестизначной формы технически делает это ненужным. (Суррогатные пары не сохраняются непосредственно, а объединяются в один символ, который затем кодируется в UTF-8.)

Идентификатор, заключённый в кавычки, становится зависимым от регистра, тогда как идентификаторы без кавычек всегда переводятся в нижний регистр. Например, идентификаторы FOO, foo и "foo" считаются одинаковыми в Postgres Pro, но "Foo" и "FOO" отличны друг от друга и от предыдущих трёх. (Приведение имён без кавычек к нижнему регистру, как это делает Postgres Pro, несовместимо со стандартом SQL, который говорит о том, что имена должны приводиться к верхнему регистру. То есть, согласно стандарту foo должно быть эквивалентно "FOO", а не "foo". Поэтому при создании переносимых приложений рекомендуется либо всегда заключать определённое имя в кавычки, либо не заключать никогда.)

## 4.1.2. Константы

В Postgres Pro есть три типа констант подразумеваемых типов: строки, битовые строки и числа. Константы можно также записывать, указывая типы явно, что позволяет представить их более точно и обработать более эффективно. Эти варианты рассматриваются в следующих подразделах.

### 4.1.2.1. Строковые константы
Строковая константа в SQL — это обычная последовательность символов, заключённая в апострофы ('), например: 'Это строка'. Чтобы включить апостроф в строку, напишите в ней два апострофа рядом, например: 'Жанна д''Арк'. Заметьте, это не то же самое, что двойная кавычка (").

Две строковые константы, разделённые пробельными символами и минимум одним переводом строки, объединяются в одну и обрабатываются, как если бы строка была записана в одной константе. Например:

    SELECT 'foo'
    'bar';
эквивалентно:

    SELECT 'foobar';
но эта запись:

    SELECT 'foo'      'bar';
считается синтаксической ошибкой. (Это несколько странное поведение определено в стандарте SQL, Postgres Pro просто следует ему.)

### 4.1.2.2. Строковые константы со спецпоследовательностями в стиле C
Postgres Pro также принимает «спецпоследовательности», что является расширением стандарта SQL. Строка со спецпоследовательностями начинается с буквы E (заглавной или строчной), стоящей непосредственно перед апострофом, например: E'foo'. (Когда константа со спецпоследовательностью разбивается на несколько строк, букву E нужно поставить только перед первым открывающим апострофом.) Внутри таких строк символ обратной косой черты (\) начинает C-подобные спецпоследовательности, в которых сочетание обратной косой черты со следующим символом(ами) даёт определённое байтовое значение, как показано в Таблице 4.1.

Таблица 4.1. Спецпоследовательности


column0 | column1
------- | -------
Спецпоследовательность | Интерпретация
\b | символ «забой»
\f | подача формы
\n | новая строка
\r | возврат каретки
\t | табуляция
\o, \oo, \ooo (o = 0 - 7) | восьмеричное значение байта
\xh, \xhh (h = 0 — 9, A — F) | шестнадцатеричное значение байта
\uxxxx, \Uxxxxxxxx (x = 0 — 9, A — F) | 16- или 32-битный шестнадцатеричный код символа Unicode

Любой другой символ, идущий после обратной косой черты, воспринимается буквально. Таким образом, чтобы включить в строку обратную косую черту, нужно написать две косых черты (\\). Так же можно включить в строку апостроф, написав \', в дополнение к обычному способу ''.

Вы должны позаботиться, чтобы байтовые последовательности, которые вы создаёте таким образом, особенно в восьмеричной и шестнадцатеричной записи, образовывали допустимые символы в серверной кодировке. Когда сервер работает с кодировкой UTF-8, вместо такой записи байт следует использовать спецпоследовательности Unicode или альтернативный синтаксис Unicode, описанный в Подразделе 4.1.2.3. (В противном случае придётся кодировать символы UTF-8 вручную и выписывать их по байтам, что очень неудобно.)

Спецпоследовательности с Unicode полностью поддерживаются только при использовании на сервере кодировки UTF8. Когда используются другие кодировки, допускается указание только ASCII-символов (с кодами до \u007F). И в четырёх, и в восьмизначной форме можно записывать суррогатные пары UTF-16 и таким образом составлять символы с кодами больше чем U+FFFF, хотя наличие восьмизначной формы технически делает это ненужным. (Когда суррогатные пары используются с серверной кодировкой UTF8, они сначала объединяются в один символ, который затем кодируется в UTF-8.)

> Внимание
Если параметр конфигурации standard_conforming_strings имеет значение off, Postgres Pro распознаёт обратную косую черту как спецсимвол и в обычных строках, и в строках со спецпоследовательностями. Однако в версии PostgreSQL 9.1 по умолчанию принято значение on, и в этом случае обратная косая черта распознаётся только в спецстроках. Это поведение больше соответствует стандарту, хотя может нарушить работу приложений, рассчитанных на предыдущий режим, когда обратная косая черта распознавалась везде. В качестве временного решения вы можете изменить этот параметр на off, но лучше уйти от такой практики. Если вам нужно, чтобы обратная косая черта представляла специальный символ, задайте строковую константу с E.

В дополнение к standard_conforming_strings поведением обратной косой черты в строковых константах управляют параметры escape_string_warning и backslash_quote.

Строковая константа не может включать символ с кодом 0.

### 4.1.2.3. Строковые константы со спецпоследовательностями Unicode
Postgres Pro также поддерживает ещё один вариант спецпоследовательностей, позволяющий включать в строки символы Unicode по их кодам. Строковая константа со спецпоследовательностями Unicode начинается с U& (строчная или заглавная U и амперсанд), а затем сразу без пробелов идёт апостроф, например U&'foo'. (Заметьте, что при этом возникает неоднозначность с оператором &. Чтобы её избежать, окружайте этот оператор пробелами.) Затем в апострофах можно записывать символы Unicode двумя способами: обратная косая черта, а за ней код символа из четырёх шестнадцатеричных цифр, либо обратная косая черта, знак плюс, а затем код из шести шестнадцатеричных цифр. Например, строку 'data' можно записать так:

    U&'d\0061t\+000061'
В следующем менее тривиальном примере закодировано русское слово «слон», записанное кириллицей:

    U&'\0441\043B\043E\043D'
Если вы хотите использовать не обратную косую черту, а другой спецсимвол, его можно указать, добавив UESCAPE после строки, например:

    U&'d!0061t!+000061' UESCAPE '!'
В качестве спецсимвола можно выбрать любой символ, кроме шестнадцатеричной цифры, знака плюс, апострофа, кавычки или пробельного символа.

Спецпоследовательности с Unicode поддерживаются только при использовании на сервере кодировки UTF8. Когда используются другие кодировки, допускается указание только ASCII-символов (с кодами до \007F). И в четырёх, и в шестизначной форме можно записывать суррогатные пары UTF-16 и таким образом составлять символы с кодами больше чем U+FFFF, хотя наличие шестизначной формы технически делает это ненужным. (Когда суррогатные пары используются с серверной кодировкой UTF8, они сначала объединяются в один символ, который затем кодируется в UTF-8.)

Также заметьте, что спецпоследовательности Unicode в строковых константах работают, только когда параметр конфигурации standard_conforming_strings равен on. Это объясняется тем, что иначе клиентские программы, проверяющие SQL-операторы, можно будет ввести в заблуждение и эксплуатировать это как уязвимость, например, для SQL-инъекций. Если этот параметр имеет значение off, эти спецпоследовательности будут вызывать ошибку.

Чтобы включить спецсимвол в строку буквально, напишите его дважды.

### 4.1.2.4. Строковые константы, заключённые в доллары
Хотя стандартный синтаксис для строковых констант обычно достаточно удобен, он может плохо читаться, когда строка содержит много апострофов или обратных косых черт, так как каждый такой символ приходится дублировать. Чтобы и в таких случаях запросы оставались читаемыми, Postgres Pro предлагает ещё один способ записи строковых констант — «заключение строк в доллары». Строковая константа, заключённая в доллары, начинается со знака доллара ($), необязательного «тега» из нескольких символов и ещё одного знака доллара, затем содержит обычную последовательность символов, составляющую строку, и оканчивается знаком доллара, тем же тегом и замыкающим знаком доллара. Например, строку «Жанна д'Арк» можно записать в долларах двумя способами:

    $$Жанна д'Арк$$
    $SomeTag$Жанна д'Арк$SomeTag$
Заметьте, что внутри такой строки апострофы не нужно записывать особым образом. На самом деле, в строке, заключённой в доллары, все символы можно записывать в чистом виде: содержимое строки всегда записывается буквально. Ни обратная косая черта, ни даже знак доллара не являются спецсимволами, если только они не образуют последовательность, соответствующую открывающему тегу.

Строковые константы в долларах можно вкладывать друг в друга, выбирая на разных уровнях вложенности разные теги. Чаще всего это используется при написании определений функций. Например:

    $function$
    BEGIN
        RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
    END;
    $function$
Здесь последовательность `$q$[\t\r\n\v\\]$q$ `представляет в долларах текстовую строку [\t\r\n\v\\], которая будет обработана, когда Postgres Pro будет выполнять эту функцию. Но так как эта последовательность не соответствует внешнему тегу в долларах ($function$), с точки зрения внешней строки это просто обычные символы внутри константы.

Тег строки в долларах, если он присутствует, должен соответствовать правилам, определённым для идентификаторов без кавычек, и к тому же не должен содержать знак доллара. Теги регистрозависимы, так что $tag$String content$tag$ — правильная строка, а $TAG$String content$tag$ — нет.

Строка в долларах, следующая за ключевым словом или идентификатором, должна отделяться от него пробельными символами, иначе доллар будет считаться продолжением предыдущего идентификатора.

Заключение строк в доллары не является частью стандарта SQL, но часто это более удобный способ записывать сложные строки, чем стандартный вариант с апострофами. Он особенно полезен, когда нужно представить строковую константу внутри другой строки, что часто требуется в определениях процедурных функций. Ограничившись только апострофами, каждую обратную косую черту в приведённом примере пришлось бы записывать четырьмя такими символами, которые бы затем уменьшились до двух при разборе внешней строки, и наконец до одного при обработке внутренней строки во время выполнения функции.

#### 4.1.2.5. Битовые строковые константы
Битовые строковые константы похожи на обычные с дополнительной буквой B (заглавной или строчной), добавленной непосредственно перед открывающим апострофом (без промежуточных пробелов), например: B'1001'. В битовых строковых константах допускаются лишь символы 0 и 1.

Битовые константы могут быть записаны и по-другому, в шестнадцатеричном виде, с начальной буквой X (заглавной или строчной), например: X'1FF'. Такая запись эквивалентна двоичной, только четыре двоичных цифры заменяются одной шестнадцатеричной.

Обе формы записи допускают перенос строк так же, как и обычные строковые константы. Однако заключать в доллары битовые строки нельзя.

#### 4.1.2.6. Числовые константы
Числовые константы могут быть заданы в следующем общем виде:

    цифры
    цифры.[цифры][e[+-]цифры]
    [цифры].цифры[e[+-]цифры]
    цифрыe[+-]цифры
где цифры — это одна или несколько десятичных цифр (0..9). До или после десятичной точки (при её наличии) должна быть минимум одна цифра. Как минимум одна цифра должна следовать за обозначением экспоненты (e), если оно присутствует. В числовой константе не может быть пробелов или других символов. Заметьте, что любой знак минус или плюс в начале строки не считается частью числа; это оператор, применённый к константе.

Несколько примеров допустимых числовых констант:


    42
    3.5
    4.
    .001
    5e2
    1.925e-3

Числовая константа, не содержащая точки и экспоненты, изначально рассматривается как константа типа integer, если её значение умещается в 32-битный тип integer; затем как константа типа bigint, если её значение умещается в 64-битный bigint; в противном случае она принимает тип numeric. Константы, содержащие десятичные точки и/или экспоненты, всегда считаются константами типа numeric.

Изначально назначенный тип данных числовой константы это только отправная точка для алгоритмов определения типа. В большинстве случаев константа будет автоматически приведена к наиболее подходящему типу для данного контекста. При необходимости вы можете принудительно интерпретировать числовое значение как значение определённого типа, приведя его тип к нужному. Например, вы можете сделать, чтобы числовое значение рассматривалось как имеющее тип real (float4), написав:

    REAL '1.23'  -- строковый стиль
    1.23::REAL   -- стиль Postgres Pro (исторический)
На самом деле это только частные случаи синтаксиса приведения типов, который будет рассматриваться далее.

#### 4.1.2.7. Константы других типов
Константу обычного типа можно ввести одним из следующих способов:

    type 'string'
    'string'::type
    CAST ( 'string' AS type )
Текст строковой константы передаётся процедуре преобразования ввода для типа, обозначенного здесь type. Результатом становится константа указанного типа. Явное приведение типа можно опустить, если нужный тип константы определяется однозначно (например, когда она присваивается непосредственно столбцу таблицы), так как в этом случае приведение происходит автоматически.

Строковую константу можно записать, используя как обычный синтаксис SQL, так и формат с долларами.

Также можно записать приведение типов, используя синтаксис функций:

    typename ( 'string' )   
но это работает не для всех имён типов; подробнее об этом написано в Подразделе 4.2.9.

Конструкцию ::, CAST() и синтаксис вызова функции можно также использовать для преобразования типов обычных выражений во время выполнения, как описано в Подразделе 4.2.9. Во избежание синтаксической неопределённости, запись тип 'строка' можно использовать только для указания типа простой текстовой константы. Ещё одно ограничение записи тип 'строка': она не работает для массивов; для таких констант следует использовать :: или CAST().

Синтаксис CAST() соответствует SQL, а запись type 'string' является обобщением стандарта: в SQL такой синтаксис поддерживает только некоторые типы данных, но Postgres Pro позволяет использовать его для всех. Синтаксис с :: имеет исторические корни в Postgres Pro, как и запись в виде вызова функции.

## 4.1.3. Операторы

Имя оператора образует последовательность не более чем NAMEDATALEN-1 (по умолчанию 63) символов из следующего списка:


 ` + - * / < > = ~ ! @ # % ^ & | ` ? `

Однако для имён операторов есть ещё несколько ограничений:

* Сочетания символов -- и /* не могут присутствовать в имени оператора, так как они будут обозначать начало комментария.

* Многосимвольное имя оператора не может заканчиваться знаком + или -, если только оно не содержит также один из этих символов:


    `~ ! @ # % ^ & | ` ? `

Например, @- — допустимое имя оператора, а *- — нет. Благодаря этому ограничению, Postgres Pro может разбирать корректные SQL-запросы без пробелов между компонентами.

Записывая нестандартные SQL-операторы, обычно нужно отделять имена соседних операторов пробелами для однозначности. Например, если вы определили левый унарный оператор с именем @, вы не можете написать X*@Y, а должны написать X* @Y, чтобы Postgres Pro однозначно прочитал это как два оператора, а не один.

## 4.1.4. Специальные знаки

Некоторые не алфавитно-цифровые символы имеют специальное значение, но при этом не являются операторами. Подробнее их использование будет рассмотрено при описании соответствующего элемента синтаксиса. Здесь они упоминаются только для сведения и обобщения их предназначения.

* Знак доллара ($), предваряющий число, используется для представления позиционного параметра в теле определения функции или подготовленного оператора. В других контекстах знак доллара может быть частью идентификатора или строковой константы, заключённой в доллары.

* Круглые скобки (()) имеют обычное значение и применяются для группировки выражений и повышения приоритета операций. В некоторых случаях скобки — это необходимая часть синтаксиса определённых SQL-команд.

* Квадратные скобки ([]) применяются для выделения элементов массива. Подробнее массивы рассматриваются в Разделе 8.15.

* Запятые (,) используются в некоторых синтаксических конструкциях для разделения элементов списка.

* Точка с запятой ; завершает команду SQL. Она не может находиться нигде внутри команды, за исключением строковых констант или идентификаторов в кавычках.

* Двоеточие : применяется для выборки «срезов» массивов (см. Раздел 8.15.) В некоторых диалектах SQL (например, в Embedded SQL) двоеточие может быть префиксом в имени переменной.

* Звёздочка * используется в некоторых контекстах как обозначение всех полей строки или составного значения. Она также имеет специальное значение, когда используется как аргумент некоторых агрегатных функций, а именно функций, которым не нужны явные параметры.

* Точка . используется в числовых константах, а также для отделения имён схемы, таблицы и столбца.

## 4.1.5. Комментарии

Комментарий — это последовательность символов, которая начинается с двух минусов и продолжается до конца строки, например:

    -- Это стандартный комментарий SQL
Кроме этого, блочные комментарии можно записывать в стиле C:

    /* многострочный комментарий
    \* с вложенностью: /* вложенный блок комментария */
    */
где комментарий начинается с /* и продолжается до соответствующего вхождения */. Блочные комментарии можно вкладывать друг в друга, как разрешено по стандарту SQL (но не разрешено в C), так что вы можете комментировать большие блоки кода, которые при этом уже могут содержать блоки комментариев.

Комментарий удаляется из входного потока в начале синтаксического анализа и фактически заменяется пробелом.

## 4.1.6. Приоритеты операторов

В Таблице 4.2 показаны приоритеты и очерёдность операторов, действующие в Postgres Pro. Большинство операторов имеют одинаковый приоритет и вычисляются слева направо. Приоритет и очерёдность операторов жёстко фиксированы в синтаксическом анализаторе.

Иногда вам потребуется добавлять скобки, когда вы комбинируете унарные и бинарные операторы. Например, выражение:

    SELECT 5 ! - 6;
будет разобрано как:

    SELECT 5 ! (- 6);
так как анализатор до последнего не знает, что оператор ! определён как постфиксный, а не инфиксный (внутренний). Чтобы получить желаемый результат в этом случае, нужно написать:

    SELECT (5 !) - 6;
Такова цена расширяемости.

Таблица 4.2. Приоритет операторов (от большего к меньшему)

Оператор/элемент | Очерёдность | Описание
-----------------|-------------|---------
. | слева-направо | разделитель имён таблицы и столбца
:: | слева-направо | приведение типов в стиле Postgres Pro
[ ] | слева-направо | выбор элемента массива
+ - | справа-налево | унарный плюс, унарный минус
^ | слева-направо | возведение в степень
* / % | слева-направо | умножение, деление, остаток от деления
+ - | слева-направо | сложение, вычитание
(любой другой оператор) | слева-направо | все другие встроенные и пользовательские операторы
BETWEEN IN LIKE ILIKE SIMILAR || проверка диапазона, проверка членства, сравнение строк
< > = <= >= <> | |операторы сравнения
IS ISNULL NOTNULL || IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM и т. д.
NOT | справа-налево | логическое отрицание
AND | слева-направо | логическая конъюнкция
OR | слева-направо | логическая дизъюнкция

Заметьте, что правила приоритета операторов также применяются к операторам, определённым пользователем с теми же именами, что и вышеперечисленные встроенные операторы. Например, если вы определите оператор «+» для некоторого нестандартного типа данных, он будет иметь тот же приоритет, что и встроенный оператор «+», независимо от того, что он у вас делает.

Когда в конструкции OPERATOR используется имя оператора со схемой, например так:

    SELECT 3 OPERATOR(pg_catalog.+) 4;
тогда OPERATOR имеет приоритет по умолчанию, соответствующий в Таблице 4.2 строке «любой другой оператор». Это не зависит от того, какие именно операторы находятся в конструкции OPERATOR().

> Примечание
В PostgreSQL до версии 9.5 действовали немного другие правила приоритета операторов. В частности, операторы <=, >= и <> обрабатывались по общему правилу; проверки IS имели более высокий приоритет; а NOT BETWEEN и связанные конструкции работали несогласованно — в некоторых случаях приоритетнее оказывался оператор NOT, а не BETWEEN. Эти правила были изменены для лучшего соответствия стандарту SQL и для уменьшения путаницы из-за несогласованной обработки логически равнозначных конструкций. В большинстве случаев эти изменения никак не проявятся, либо могут привести к ошибкам типа «нет такого оператора», которые можно разрешить, добавив скобки. Однако, возможны особые случаи, когда запрос будет разобран без ошибки, но его поведение может измениться. Если вас беспокоит, не нарушают ли эти изменения незаметно работу вашего приложения, вы можете проверить это, включив конфигурационный параметр operator_precedence_warning и пронаблюдав, не появятся ли предупреждения в журнале.

#  [4.2. Выражения значения](https://postgrespro.ru/docs/postgrespro/12/sql-expressions)
[sql-expressions.sql](\tutorial-sql\sql-syntax\sql-expressions.sql)
Node_Way\NBase\_Md\_Index\_Postgres\postgrespro.ru_12\content\tutorial-sql\sql-syntax\sql-expressions.sql
Выражения значения применяются в самых разных контекстах, например в списке результатов команды SELECT, в значениях столбцов в INSERT или UPDATE или в условиях поиска во многих командах. Результат такого выражения иногда называют скаляром, чтобы отличить его от результата табличного выражения (который представляет собой таблицу). А сами выражения значения часто называют скалярными (или просто выражениями). Синтаксис таких выражений позволяет вычислять значения из примитивных частей, используя арифметические, логические и другие операции.

Выражениями значения являются:

* Константа или непосредственное значение

* Ссылка на столбец

* Ссылка на позиционный параметр в теле определения функции или подготовленного оператора

* Выражение с индексом

* Выражение выбора поля

* Применение оператора

* Вызов функции

* Агрегатное выражение

* Вызов оконной функции

* Приведение типов

* Применение правил сортировки

* Скалярный подзапрос

* Конструктор массива

* Конструктор табличной строки

* Кроме того, выражением значения являются скобки (предназначенные для группировки подвыражений и переопределения приоритета )

В дополнение к этому списку есть ещё несколько конструкций, которые можно классифицировать как выражения, хотя они не соответствуют общим синтаксическим правилам. Они обычно имеют вид функции или оператора и будут рассмотрены в соответствующем разделе Главы 9. Пример такой конструкции — предложение IS NULL.

Мы уже обсудили константы в Подразделе 4.1.2. В следующих разделах рассматриваются остальные варианты.

## 4.2.1.  Ссылки на столбцы

Ссылку на столбец можно записать в форме:

    отношение.имя_столбца
Здесь отношение — имя таблицы (возможно, полное, с именем схемы) или её псевдоним, определённый в предложении FROM. Это имя и разделяющую точку можно опустить, если имя столбца уникально среди всех таблиц, задействованных в текущем запросе. (См. также Главу 7.)

## 4.2.2.  Позиционные параметры

Ссылка на позиционный параметр применяется для обращения к значению, переданному в SQL-оператор извне. Параметры используются в определениях SQL-функций и подготовленных операторов. Некоторые клиентские библиотеки также поддерживают передачу значений данных отдельно от самой SQL-команды, и в этом случае параметры позволяют ссылаться на такие значения. Ссылка на параметр записывается в следующей форме:

    $число
Например, рассмотрим следующее определение функции dept:

    CREATE FUNCTION dept(text) RETURNS dept
        AS $$ SELECT * FROM dept WHERE name = $1 $$
        LANGUAGE SQL;
Здесь $1 всегда будет ссылаться на значение первого аргумента функции.

## 4.2.3.  Индексы элементов

Если в выражении вы имеете дело с массивом, то можно извлечь определённый его элемент, написав:

    выражение[индекс]
или несколько соседних элементов («срез массива»):

    выражение[нижний_индекс:верхний_индекс]
(Здесь квадратные скобки [ ] должны быть в явном виде.) Каждый индекс сам по себе является выражением, результатом которого должно быть целое число.

В общем случае выражение массива должно заключаться в круглые скобки, но их можно опустить, когда выражение с индексом — это просто ссылка на столбец или позиционный параметр. Кроме того, можно соединить несколько индексов, если исходный массив многомерный. Например:

    моя_таблица.столбец_массив[4]
    моя_таблица.столбец_массив_2d[17][34]
    $1[10:42]
    (функция_массив(a,b))[42]
В последней строке круглые скобки необходимы. Подробнее массивы рассматриваются в Разделе 8.15.

## 4.2.4.  Выбор поля

Если результат выражения — значение составного типа (строка таблицы), тогда определённое поле этой строки можно извлечь, написав:

выражение.имя_поля
В общем случае выражение такого типа должно заключаться в круглые скобки, но их можно опустить, когда это ссылка на таблицу или позиционный параметр. Например:

    моя_таблица.столбец
    $1.столбец
    (функция_кортеж(a,b)).стол3
(Таким образом, полная ссылка на столбец — это просто частный случай выбора поля.) Важный особый случай здесь — извлечение поля из столбца составного типа:

    (составной_столбец).поле
    (моя_таблица.составной_столбец).поле
Здесь скобки нужны, чтобы показать, что составной_столбец — это имя столбца, а не таблицы, и что моя_таблица — имя таблицы, а не схемы.

Вы можете запросить все поля составного значения, написав .*:

    (составной_столбец).*
Эта запись действует по-разному в зависимости от контекста; подробнее об этом говорится в Подразделе 8.16.5.

## 4.2.5.  Применение оператора

Существуют три возможных синтаксиса применения операторов:

    выражение оператор выражение (бинарный инфиксный оператор)
    оператор выражение (унарный префиксный оператор)
    выражение оператор (унарный постфиксный оператор)

где оператор соответствует синтаксическим правилам, описанным в Подразделе 4.1.3, либо это одно из ключевых слов AND, OR и NOT, либо полное имя оператора в форме:

    OPERATOR(схема.имя_оператора)
Существование конкретных операторов и их тип (унарный или бинарный) зависит от того, как и какие операторы определены системой и пользователем. Встроенные операторы описаны в Главе 9.

## 4.2.6.  Вызовы функций

Вызов функции записывается просто как имя функции (возможно, дополненное именем схемы) и список аргументов в скобках:

    имя_функции ([выражение [, выражение ... ]])
Например, так вычисляется квадратный корень из 2:

    sqrt(2)
Список встроенных функций приведён в Главе 9. Пользователь также может определить и другие функции.

Выполняя запросы в базе данных, где одни пользователи могут не доверять другим, в записи вызовов функций соблюдайте меры предосторожности, описанные в Разделе 10.3.

Аргументам могут быть присвоены необязательные имена. Подробнее об этом см. Раздел 4.3.

> Примечание
Функцию, принимающую один аргумент составного типа, можно также вызывать, используя синтаксис выбора поля, и наоборот, выбор поля можно записать в функциональном стиле. То есть записи col(table) и table.col равносильны и взаимозаменяемы. Это поведение не оговорено стандартом SQL, но реализовано в Postgres Pro, так как это позволяет использовать функции для эмуляции «вычисляемых полей». Подробнее это описано в Подразделе 8.16.5.

## 4.2.7.  Агрегатные выражения

Агрегатное выражение представляет собой применение агрегатной функции к строкам, выбранным запросом. Агрегатная функция сводит множество входных значений к одному выходному, как например, сумма или среднее. Агрегатное выражение может записываться следующим образом:

    агрегатная_функция (выражение [ , ... ] [ предложение_order_by ] ) [ FILTER ( WHERE условие_фильтра ) ]
    агрегатная_функция (ALL выражение [ , ... ] [ предложение_order_by ] ) [ FILTER ( WHERE условие_фильтра ) ]
    агрегатная_функция (DISTINCT выражение [ , ... ] [ предложение_order_by ] ) [ FILTER ( WHERE условие_фильтра ) ]
    агрегатная_функция ( * ) [ FILTER ( WHERE условие_фильтра ) ]
    агрегатная_функция ( [ выражение [ , ... ] ] ) WITHIN GROUP ( предложение_order_by ) [ FILTER ( WHERE условие_фильтра ) ]

Здесь агрегатная_функция — имя ранее определённой агрегатной функции (возможно, дополненное именем схемы), выражение — любое выражение значения, не содержащее в себе агрегатного выражения или вызова оконной функции. Необязательные предложения предложение_order_by и условие_фильтра описываются ниже.

В первой форме агрегатного выражения агрегатная функция вызывается для каждой строки. Вторая форма эквивалентна первой, так как указание ALL подразумевается по умолчанию. В третьей форме агрегатная функция вызывается для всех различных значений выражения (или набора различных значений, для нескольких выражений), выделенных во входных данных. В четвёртой форме агрегатная функция вызывается для каждой строки, так как никакого конкретного значения не указано (обычно это имеет смысл только для функции count(*)). В последней форме используются сортирующие агрегатные функции, которые будут описаны ниже.

Большинство агрегатных функций игнорируют значения NULL, так что строки, для которых выражения выдают одно или несколько значений NULL, отбрасываются. Это можно считать истинным для всех встроенных операторов, если явно не говорится об обратном.

Например, count(*) подсчитает общее количество строк, а count(f1) только количество строк, в которых f1 не NULL (так как count игнорирует NULL), а count(distinct f1) подсчитает число различных и отличных от NULL значений столбца f1.

Обычно строки данных передаются агрегатной функции в неопределённом порядке и во многих случаях это не имеет значения, например функция min выдаёт один и тот же результат независимо от порядка поступающих данных. Однако некоторые агрегатные функции (такие как array_agg и string_agg) выдают результаты, зависящие от порядка данных. Для таких агрегатных функций можно добавить предложение_order_by и задать нужный порядок. Это предложение_order_by имеет тот же синтаксис, что и предложение ORDER BY на уровне запроса, как описано в Разделе 7.5, за исключением того, что его выражения должны быть просто выражениями, а не именами результирующих столбцов или числами. Например:

    SELECT array_agg(a ORDER BY b DESC) FROM table;
Заметьте, что при использовании агрегатных функций с несколькими аргументами, предложение ORDER BY идёт после всех аргументов. Например, надо писать так:

    SELECT string_agg(a, ',' ORDER BY a) FROM table;
а не так:

    SELECT string_agg(a ORDER BY a, ',') FROM table;  -- неправильно
Последний вариант синтаксически допустим, но он представляет собой вызов агрегатной функции одного аргумента с двумя ключами ORDER BY (при этом второй не имеет смысла, так как это константа).

Если предложение_order_by дополнено указанием DISTINCT, тогда все выражения ORDER BY должны соответствовать обычным аргументам агрегатной функции; то есть вы не можете сортировать строки по выражению, не включённому в список DISTINCT.

> Примечание
Возможность указывать и DISTINCT, и ORDER BY в агрегатной функции — это расширение Postgres Pro.

При добавлении ORDER BY в обычный список аргументов агрегатной функции, описанном до этого, выполняется сортировка входных строк для универсальных и статистических агрегатных функций, для которых сортировка необязательна. Но есть подмножество агрегатных функций, сортирующие агрегатные функции, для которых предложение_order является обязательным, обычно потому, что вычисление этой функции имеет смысл только при определённой сортировке входных строк. Типичными примерами сортирующих агрегатных функций являются вычисления ранга и процентиля. Для сортирующей агрегатной функции предложение_order_by записывается внутри WITHIN GROUP (...), что иллюстрирует последний пример, приведённый выше. Выражения в предложении_order_by вычисляются однократно для каждой входной строки как аргументы обычной агрегатной функции, сортируются в соответствии с требованием предложения_order_by и поступают в агрегатную функции как входящие аргументы. (Если же предложение_order_by находится не в WITHIN GROUP, оно не передаётся как аргумент(ы) агрегатной функции.) Выражения-аргументы, предшествующие WITHIN GROUP, (если они есть), называются непосредственными аргументами, а выражения, указанные в предложении_order_by — агрегируемыми аргументами. В отличие от аргументов обычной агрегатной функции, непосредственные аргументы вычисляются однократно для каждого вызова функции, а не для каждой строки. Это значит, что они могут содержать переменные, только если эти переменные сгруппированы в GROUP BY; это суть то же ограничение, что действовало бы, будь эти непосредственные аргументы вне агрегатного выражения. Непосредственные аргументы обычно используются, например, для указания значения процентиля, которое имеет смысл, только если это конкретное число для всего расчёта агрегатной функции. Список непосредственных аргументов может быть пуст; в этом случае запишите просто (), но не (*). (На самом деле Postgres Pro примет обе записи, но только первая соответствует стандарту SQL.)

Пример вызова сортирующей агрегатной функции:

 ### percentile_cont
    SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY income) FROM households;
    percentile_cont
    -----------------
            50489
она получает 50-ый процентиль, или медиану, значения столбца income из таблицы households. В данном случае 0.5 — это непосредственный аргумент; если бы дробь процентиля менялась от строки к строке, это не имело бы смысла.

Если добавлено предложение FILTER, агрегатной функции подаются только те входные строки, для которых условие_фильтра вычисляется как истинное; другие строки отбрасываются. Например:

### generate_series
    SELECT
        count(*) AS unfiltered,
        count(*) FILTER (WHERE i < 5) AS filtered
    FROM generate_series(1,10) AS s(i);
    unfiltered | filtered
    ------------+----------
            10 |        4
    (1 row)
Предопределённые агрегатные функции описаны в Разделе 9.20. Пользователь также может определить другие агрегатные функции.

Агрегатное выражение может фигурировать только в списке результатов или в предложении HAVING команды SELECT. Во всех остальных предложениях, например WHERE, они запрещены, так как эти предложения логически вычисляются до того, как формируются результаты агрегатных функций.

Когда агрегатное выражение используется в подзапросе (см. Подраздел 4.2.11 и Раздел 9.22), оно обычно вычисляется для всех строк подзапроса. Но если в аргументах (или в условии_filter) агрегатной функции есть только переменные внешнего уровня, агрегатная функция относится к ближайшему внешнему уровню и вычисляется для всех строк соответствующего запроса. Такое агрегатное выражение в целом является внешней ссылкой для своего подзапроса и на каждом вычислении считается константой. При этом допустимое положение агрегатной функции ограничивается списком результатов и предложением HAVING на том уровне запросов, где она находится.

## 4.2.8.  Вызовы оконных функций

Вызов оконной функции представляет собой применение функции, подобной агрегатной, к некоторому набору строк, выбранному запросом. В отличие от вызовов не оконных агрегатных функций, при этом не происходит группировка выбранных строк в одну — каждая строка остаётся отдельной в результате запроса. Однако оконная функция имеет доступ ко всем строкам, вошедшим в группу текущей строки согласно указанию группировки (списку PARTITION BY) в вызове оконной функции. Вызов оконной функции может иметь следующие формы:

### форма вызова

    имя_функции ([выражение [, выражение ... ]]) [ FILTER ( WHERE предложение_фильтра ) ] OVER имя_окна
    имя_функции ([выражение [, выражение ... ]]) [ FILTER ( WHERE предложение_фильтра ) ] OVER ( определение_окна )
    имя_функции ( * ) [ FILTER ( WHERE предложение_фильтра ) ] OVER имя_окна
    имя_функции ( * ) [ FILTER ( WHERE предложение_фильтра ) ] OVER ( определение_окна )
Здесь определение_окна записывается в виде

### определение_окна

    [ имя_существующего_окна ]
    [ PARTITION BY выражение [, ...] ]
    [ ORDER BY выражение [ ASC | DESC | USING оператор ] [ NULLS { FIRST | LAST } ] [, ...] ]
    [ определение_рамки ]
Необязательное определение_рамки может иметь вид:

### определение_рамки
    { RANGE | ROWS | GROUPS } начало_рамки [ исключение_рамки ]
    { RANGE | ROWS | GROUPS } BETWEEN начало_рамки AND конец_рамки [ исключение_рамки ]
Здесь начало_рамки и конец_рамки задаются одним из следующих способов:

### начало_рамки и конец_рамки
    UNBOUNDED PRECEDING
    смещение PRECEDING
    CURRENT ROW
    смещение FOLLOWING
    UNBOUNDED FOLLOWING
и исключение_рамки может быть следующим:

### исключение_рамки
    EXCLUDE CURRENT ROW
    EXCLUDE GROUP
    EXCLUDE TIES
    EXCLUDE NO OTHERS
Здесь выражение — это любое выражение значения, не содержащее вызовов оконных функций.

имя_окна — ссылка на именованное окно, определённое предложением WINDOW в данном запросе. Также возможно написать в скобках полное определение_окна, используя тот же синтаксис определения именованного окна в предложении WINDOW; подробнее это описано в справке по SELECT. Стоит отметить, что запись OVER имя_окна не полностью равнозначна OVER (имя_окна ...); последний вариант подразумевает копирование и изменение определения окна и не будет допустимым, если определение этого окна включает определение рамки.

### PARTITION BY
Указание PARTITION BY группирует строки запроса в разделы, которые затем обрабатываются оконной функцией независимо друг от друга. PARTITION BY работает подобно предложению GROUP BY на уровне запроса, за исключением того, что его аргументы всегда просто выражения, а не имена выходных столбцов или числа. Без PARTITION BY все строки, выдаваемые запросом, рассматриваются как один раздел. Указание ORDER BY определяет порядок, в котором оконная функция обрабатывает строки раздела. Оно так же подобно предложению ORDER BY на уровне запроса и так же не принимает имена выходных столбцов или числа. Без ORDER BY строки обрабатываются в неопределённом порядке.

определение_рамки задаёт набор строк, образующих рамку окна, которая представляет собой подмножество строк текущего раздела и используется для оконных функций, работающих с рамкой, а не со всем разделом. Подмножество строк в рамке может меняться в зависимости от того, какая строка является текущей. Рамку можно задать в режимах RANGE, ROWS или GROUPS; в каждом случае она начинается с положения начало_рамки и заканчивается положением конец_рамки. Если конец_рамки не задаётся явно, подразумевается CURRENT ROW (текущая строка).

### UNBOUNDED
Если начало_рамки задано как UNBOUNDED PRECEDING, рамка начинается с первой строки раздела, а если конец_рамки определён как UNBOUNDED FOLLOWING, рамка заканчивается последней строкой раздела.

В режиме RANGE или GROUPS начало_рамки, заданное как CURRENT ROW, определяет в качестве начала первую родственную строку (строку, которая при сортировке согласно указанному для окна предложению ORDER BY считается равной текущей), тогда как конец_рамки, заданный как CURRENT ROW, определяет концом рамки последнюю родственную строку. В режиме ROWS вариант CURRENT ROW просто обозначает текущую строку.

В вариантах определения рамки смещение PRECEDING и смещение FOLLOWING в качестве смещения должно задаваться выражение, не содержащее какие-либо переменные и вызовы агрегатных или оконных функций. Что именно будет означать смещение, определяется в зависимости от режима рамки:

* В режиме ROWS смещение должно задаваться отличным от NULL неотрицательным целым числом, и это число определяет сдвиг, с которым начало рамки позиционируется перед текущей строкой, а конец — после текущей строки.

* В режиме GROUPS смещение также должно задаваться отличным от NULL неотрицательным целым числом, и это число определяет сдвиг (по количеству групп родственных строк), с которым начало рамки позиционируется перед группой строк, родственных текущей, а конец — после этой группы. Группу родственных строк образуют строки, которые считаются равными согласно ORDER BY. (Для использования режима GROUPS определение окна должно содержать предложение ORDER BY.)

* В режиме RANGE для использования этих указаний предложение ORDER BY должно содержать ровно один столбец. В этом случае смещение задаёт максимальную разницу между значением этого столбца в текущей строке и значением его же в предшествующих или последующих строках рамки. Тип данных выражения смещение зависит от типа данных упорядочивающего столбца. Для числовых столбцов это обычно тот же числовой тип, а для столбцов с типом дата/время — тип interval. Например, если упорядочивающий столбец имеет тип date или timestamp, возможна такая запись: RANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING. Значение смещение при этом может так же быть отличным от NULL и неотрицательным, хотя что считать «неотрицательным», будет зависит от типа данных.

В любом случае расстояние до конца рамки ограничивается расстоянием до конца раздела, так что для строк, которые находятся у конца раздела, рамка может содержать меньше строк, чем для других.

Заметьте, что в режимах ROWS и GROUPS указания 0 PRECEDING и 0 FOLLOWING равнозначны указанию CURRENT ROW. Обычно это справедливо и для режима RANGE, в случае подходящего для типа данных определения значения «нуля».

Дополнение исключение_рамки позволяет исключить из рамки строки, которые окружают текущую строку, даже если они должны быть включены согласно указаниям, определяющим начало и конец рамки. EXCLUDE CURRENT ROW исключает из рамки текущую строку. EXCLUDE GROUP исключает из рамки текущую строку и родственные ей согласно порядку сортировки. EXCLUDE TIES исключает из рамки все родственные строки для текущей, но не собственно текущую строку. EXCLUDE NO OTHERS просто явно выражает поведение по умолчанию — не исключает ни текущую строку, ни родственные ей.

По умолчанию рамка определяется как RANGE UNBOUNDED PRECEDING, что равносильно расширенному определению RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. С указанием ORDER BY это означает, что рамка будет включать все строки от начала раздела до последней строки, родственной текущей (для ORDER BY). Без ORDER BY это означает, что в рамку включаются все строки раздела, так как все они считаются родственными текущей.

Действуют также следующие ограничения: в качестве начала_рамки нельзя задать UNBOUNDED FOLLOWING, в качестве конца_рамки не допускается UNBOUNDED PRECEDING и конец_рамки не может идти в показанном выше списке указаний начало_рамки AND конец_рамки перед началом_рамки. В частности, синтаксис RANGE BETWEEN CURRENT ROW AND смещение PRECEDING не допускается. Но при этом, например, определение ROWS BETWEEN 7 PRECEDING AND 8 PRECEDING допустимо, хотя оно и не выберет никакие строки.

Если добавлено предложение FILTER, оконной функции подаются только те входные строки, для которых условие_фильтра вычисляется как истинное; другие строки отбрасываются. Предложение FILTER допускается только для агрегирующих оконных функций.

Встроенные оконные функции описаны в Таблице 9.60, но пользователь может расширить этот набор, создавая собственные функции. Кроме того, в качестве оконных функций можно использовать любые встроенные или пользовательские универсальные, а также статистические агрегатные функции. (Сортирующие и гипотезирующие агрегатные функции в настоящее время использовать в качестве оконных нельзя.)

Запись со звёздочкой (*) применяется при вызове не имеющих параметров агрегатных функций в качестве оконных, например count(*) OVER (PARTITION BY x ORDER BY y). Звёздочка (*) обычно не применяется для исключительно оконных функций. Такие функции не допускают использования DISTINCT и ORDER BY в списке аргументов функции.

Вызовы оконных функций разрешены в запросах только в списке SELECT и в предложении ORDER BY.

Дополнительно об оконных функциях можно узнать в Разделе 3.5, Разделе 9.21 и Подразделе 7.2.5.

## 4.2.9.  Приведения типов

Приведение типа определяет преобразование данных из одного типа в другой. Postgres Pro воспринимает две равносильные записи приведения типов:

    CAST ( выражение AS тип )
    выражение::тип
Запись с CAST соответствует стандарту SQL, тогда как вариант с :: — историческое наследие Postgres Pro.

Когда приведению подвергается значение выражения известного типа, происходит преобразование типа во время выполнения. Это приведение будет успешным, только если определён подходящий оператор преобразования типов. Обратите внимание на небольшое отличие от приведения констант, описанного в Подразделе 4.1.2.7. Приведение строки в чистом виде представляет собой начальное присваивание строковой константы и оно будет успешным для любого типа (конечно, если строка содержит значение, приемлемое для данного типа данных).

Неявное приведение типа можно опустить, если возможно однозначно определить, какой тип должно иметь выражение (например, когда оно присваивается столбцу таблицы); в таких случаях система автоматически преобразует тип. Однако автоматическое преобразование выполняется только для приведений с пометкой «допускается неявное применение» в системных каталогах. Все остальные приведения должны записываться явно. Это ограничение позволяет избежать сюрпризов с неявным преобразованием.

Также можно записать приведение типа как вызов функции:

### как вызов функции
    имя_типа ( выражение )
Однако это будет работать только для типов, имена которых являются также допустимыми именами функций. Например, double precision так использовать нельзя, а float8 (альтернативное название того же типа) — можно. Кроме того, имена типов interval, time и timestamp из-за синтаксического конфликта можно использовать в такой записи только в кавычках. Таким образом, запись приведения типа в виде вызова функции провоцирует несоответствия и, возможно, лучше будет её не применять.

> Примечание
Приведение типа, представленное в виде вызова функции, на самом деле соответствует внутреннему механизму. Даже при использовании двух стандартных типов записи внутри происходит вызов зарегистрированной функции, выполняющей преобразование. По соглашению именем такой функции преобразования является имя выходного типа, и таким образом запись «в виде вызова функции» есть не что иное, как прямой вызов нижележащей функции преобразования. При создании переносимого приложения на это поведение, конечно, не следует рассчитывать. Подробнее это описано в справке CREATE CAST.

## 4.2.10.  Применение правил сортировки

Предложение COLLATE переопределяет правило сортировки выражения. Оно добавляется после выражения:

### COLLATE
    выражение COLLATE правило_сортировки
где правило_сортировки — идентификатор правила, возможно дополненный именем схемы. Предложение COLLATE связывает выражение сильнее, чем операторы, так что при необходимости следует использовать скобки.

Если правило сортировки не определено явно, система либо выбирает его по столбцам, которые используются в выражении, либо, если таких столбцов нет, переключается на установленное для базы данных правило сортировки по умолчанию.

Предложение COLLATE имеет два распространённых применения: переопределение порядка сортировки в предложении ORDER BY, например:

    SELECT a, b, c FROM tbl WHERE ... ORDER BY a COLLATE "C";
и переопределение правил сортировки при вызове функций или операторов, возвращающих языкозависимые результаты, например:

    SELECT * FROM tbl WHERE a > 'foo' COLLATE "C";
Заметьте, что в последнем случае предложение COLLATE добавлено к аргументу оператора, на действие которого мы хотим повлиять. При этом не имеет значения, к какому именно аргументу оператора или функции добавляется COLLATE, так как правило сортировки, применяемое к оператору или функции, выбирается при рассмотрении всех аргументов, а явное предложение COLLATE переопределяет правила сортировки для всех других аргументов. (Однако добавление разных предложений COLLATE к нескольким аргументам будет ошибкой. Подробнее об этом см. Раздел 22.2.) Таким образом, эта команда выдаст тот же результат:

    SELECT * FROM tbl WHERE a COLLATE "C" > 'foo';
Но это будет ошибкой:

    SELECT * FROM tbl WHERE (a > 'foo') COLLATE "C";
здесь правило сортировки нельзя применить к результату оператора >, который имеет несравниваемый тип данных boolean.

## 4.2.11. Скалярные подзапросы

Скалярный подзапрос — это обычный запрос SELECT в скобках, который возвращает ровно одну строку и один столбец. (Написание запросов освещается в Главе 7.) После выполнения запроса SELECT его единственный результат используется в окружающем его выражении. В качестве скалярного подзапроса нельзя использовать запросы, возвращающие более одной строки или столбца. (Но если в результате выполнения подзапрос не вернёт строк, скалярный результат считается равным NULL.) В подзапросе можно ссылаться на переменные из окружающего запроса; в процессе одного вычисления подзапроса они будут считаться константами. Другие выражения с подзапросами описаны в Разделе 9.22.

Например, следующий запрос находит самый населённый город в каждом штате:

    SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name)
        FROM states;

## 4.2.12. Конструкторы массивов

Конструктор массива — это выражение, которое создаёт массив, определяя значения его элементов. Конструктор простого массива состоит из ключевого слова ARRAY, открывающей квадратной скобки [, списка выражений (разделённых запятыми), задающих значения элементов массива, и закрывающей квадратной скобки ]. Например:

    SELECT ARRAY[1,2,3+4];
    array
    ---------
    {1,2,7}
    (1 row)
По умолчанию типом элементов массива считается общий тип для всех выражений, определённый по правилам, действующим и для конструкций UNION и CASE (см. Раздел 10.5). Вы можете переопределить его явно, приведя конструктор массива к требуемому типу, например:

    SELECT ARRAY[1,2,22.7]::integer[];
    array
    ----------
    {1,2,23}
    (1 row)
Это равносильно тому, что привести к нужному типу каждое выражение по отдельности. Подробнее приведение типов описано в Подразделе 4.2.9.

Многомерные массивы можно образовывать, вкладывая конструкторы массивов. При этом во внутренних конструкторах слово ARRAY можно опускать. Например, результат работы этих конструкторов одинаков:

    SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]];
        array
    ---------------
    {{1,2},{3,4}}
    (1 row)

    SELECT ARRAY[[1,2],[3,4]];
        array
    ---------------
    {{1,2},{3,4}}
    (1 row)
Многомерные массивы должны быть прямоугольными, и поэтому внутренние конструкторы одного уровня должны создавать вложенные массивы одинаковой размерности. Любое приведение типа, применённое к внешнему конструктору ARRAY, автоматически распространяется на все внутренние.

Элементы многомерного массива можно создавать не только вложенными конструкторами ARRAY, но и другими способами, позволяющими получить массивы нужного типа. Например:

### array from create table
    CREATE TABLE arr(f1 int[], f2 int[]);

    INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]);

    SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr;
                        array
    ------------------------------------------------
    {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}}
    (1 row)
Вы можете создать и пустой массив, но так как массив не может быть не типизированным, вы должны явно привести пустой массив к нужному типу. Например:

### empty array
    SELECT ARRAY[]::integer[];
    array
    -------
    {}
    (1 row)
Также возможно создать массив из результатов подзапроса. В этом случае конструктор массива записывается так же с ключевым словом ARRAY, за которым в круглых скобках следует подзапрос. Например:

### crate as result of subquery
    SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
                                    array
    -----------------------------------------------------------------------
    {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31,2412,2413}
    (1 row)

#### with generate_series
    SELECT ARRAY(SELECT ARRAY[i, i*2] FROM generate_series(1,5) AS a(i));
                array
    ----------------------------------
    {{1,2},{2,4},{3,6},{4,8},{5,10}}
    (1 row)
Такой подзапрос должен возвращать один столбец. Если этот столбец имеет тип, отличный от массива, результирующий одномерный массив будет включать элементы для каждой строки-результата подзапроса и типом элемента будет тип столбца результата. Если же тип столбца — массив, будет создан массив того же типа, но большей размерности; в любом случае во всех строках подзапроса должны выдаваться массивы одинаковой размерности, чтобы можно было получить прямоугольный результат.

Индексы массива, созданного конструктором ARRAY, всегда начинаются с одного. Подробнее о массивах вы узнаете в Разделе 8.15.

## 4.2.13. Конструкторы табличных строк

Конструктор табличной строки — это выражение, создающее строку или кортеж (или составное значение) из значений его аргументов-полей. Конструктор строки состоит из ключевого слова ROW, открывающей круглой скобки, нуля или нескольких выражений (разделённых запятыми), определяющих значения полей, и закрывающей скобки. Например:

    SELECT ROW(1,2.5,'this is a test');
Если в списке более одного выражения, ключевое слово ROW можно опустить.

Конструктор строки поддерживает запись составное_значение.*, при этом данное значение будет развёрнуто в список элементов, так же, как в записи .* на верхнем уровне списка SELECT (см. Подраздел 8.16.5). Например, если таблица t содержит столбцы f1 и f2, эти записи равнозначны:

    SELECT ROW(t.*, 42) FROM t;
    SELECT ROW(t.f1, t.f2, 42) FROM t;
> Примечание
До версии PostgreSQL 8.2 запись .* не разворачивалась в конструкторах строк, так что выражение ROW(t.*, 42) создавало составное значение из двух полей, в котором первое поле так же было составным. Новое поведение обычно более полезно. Если вам нужно получить прежнее поведение, чтобы одно значение строки было вложено в другое, напишите внутреннее значение без .*, например: ROW(t, 42).

По умолчанию значение, созданное выражением ROW, имеет тип анонимной записи. Если необходимо, его можно привести к именованному составному типу — либо к типу строки таблицы, либо составному типу, созданному оператором CREATE TYPE AS. Явное приведение может потребоваться для достижения однозначности. Например:

    CREATE TABLE mytable(f1 int, f2 float, f3 text);

    CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;

    -- Приведение не требуется, так как существует только одна getf1()
    SELECT getf1(ROW(1,2.5,'this is a test'));
    getf1
    -------
        1
    (1 row)

    CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric);

    CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;

    -- Теперь приведение необходимо для однозначного выбора функции:
    SELECT getf1(ROW(1,2.5,'this is a test'));
    ОШИБКА:  функция getf1(record) не уникальна

    SELECT getf1(ROW(1,2.5,'this is a test')::mytable);
    getf1
    -------
        1
    (1 row)

    SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype));
    getf1
    -------
        11
    (1 row)
Используя конструктор строк (кортежей), можно создавать составное значение для сохранения в столбце составного типа или для передачи функции, принимающей составной параметр. Также вы можете сравнить два составных значения или проверить их с помощью IS NULL или IS NOT NULL, например:

    SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same');

    -- выбрать все строки, содержащие только NULL
    SELECT ROW(table.*) IS NULL FROM table;
Подробнее см. Раздел 9.23. Конструкторы строк также могут использоваться в сочетании с подзапросами, как описано в Разделе 9.22.

## 4.2.14. Правила вычисления выражений

Порядок вычисления подвыражений не определён. В частности, аргументы оператора или функции не обязательно вычисляются слева направо или в любом другом фиксированном порядке.

Более того, если результат выражения можно получить, вычисляя только некоторые его части, тогда другие подвыражения не будут вычисляться вовсе. Например, если написать:

    SELECT true OR somefunc();
тогда функция somefunc() не будет вызываться (возможно). То же самое справедливо для записи:

    SELECT somefunc() OR true;
Заметьте, что это отличается от «оптимизации» вычисления логических операторов слева направо, реализованной в некоторых языках программирования.

Как следствие, в сложных выражениях не стоит использовать функции с побочными эффектами. Особенно опасно рассчитывать на порядок вычисления или побочные эффекты в предложениях WHERE и HAVING, так как эти предложения тщательно оптимизируются при построении плана выполнения. Логические выражения (сочетания AND/OR/NOT) в этих предложениях могут быть видоизменены любым способом, допустимым законами Булевой алгебры.

Когда порядок вычисления важен, его можно зафиксировать с помощью конструкции CASE (см. Раздел 9.17). Например, такой способ избежать деления на ноль в предложении WHERE ненадёжен:

    SELECT ... WHERE x > 0 AND y/x > 1.5;
Безопасный вариант:

    SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Применяемая так конструкция CASE защищает выражение от оптимизации, поэтому использовать её нужно только при необходимости. (В данном случае было бы лучше решить проблему, переписав условие как y > 1.5*x.)

Однако, CASE не всегда спасает в подобных случаях. Показанный выше приём плох тем, что не предотвращает раннее вычисление константных подвыражений. Как описано в Разделе 36.7, функции и операторы, помеченные как IMMUTABLE, могут вычисляться при планировании, а не выполнении запроса. Поэтому в примере

    SELECT CASE WHEN x > 0 THEN x ELSE 1/0 END FROM tab;
, скорее всего, произойдёт деление на ноль из-за того, что планировщик попытается упростить константное подвыражение, даже если во всех строках в таблице x > 0, а значит во время выполнения ветвь ELSE никогда не будет выполняться.

Хотя этот конкретный пример может показаться надуманным, похожие ситуации, в которых неявно появляются константы, могут возникать и в запросах внутри функций, так как значения аргументов функции и локальных переменных при планировании могут быть заменены константами. Поэтому, например, в функциях PL/pgSQL гораздо безопаснее для защиты от рискованных вычислений использовать конструкцию IF-THEN-ELSE, чем выражение CASE.

Ещё один подобный недостаток этого подхода в том, что CASE не может предотвратить вычисление заключённого в нём агрегатного выражения, так как агрегатные выражения вычисляются перед всеми остальными в списке SELECT или предложении HAVING. Например, в следующем запросе может возникнуть ошибка деления на ноль, несмотря на то, что он вроде бы защищён от неё:

    SELECT CASE WHEN min(employees) > 0
                THEN avg(expenses / employees)
        END
        FROM departments;
Агрегатные функции min() и avg() вычисляются независимо по всем входным строкам, так что если в какой-то строке поле employees окажется равным нулю, деление на ноль произойдёт раньше, чем станет возможным проверить результат функции min(). Поэтому, чтобы проблемные входные строки изначально не попали в агрегатную функцию, следует воспользоваться предложениями WHERE или FILTER.



# [4.3. Вызов функций](https://postgrespro.ru/docs/postgrespro/12/sql-syntax-calling-funcs)

Postgres Pro позволяет вызывать функции с именованными параметрами, используя запись с позиционной или именной передачей аргументов. Именная передача особенно полезна для функций со множеством параметров, так как она делает связь параметров и аргументов более явной и надёжной. В позиционной записи значения аргументов функции указываются в том же порядке, в каком они описаны в определении функции. При именной передаче аргументы сопоставляются с параметрами функции по именам и указывать их можно в любом порядке. Для каждого варианта вызова также учитывайте влияние типов аргументов функций, описанное в Разделе 10.3.

При записи любым способом параметры, для которых в определении функции заданы значения по умолчанию, можно вовсе не указывать. Но это особенно полезно при именной передаче, так как опустить можно любой набор параметров, тогда как при позиционной параметры можно опускать только последовательно, справа налево.

Postgres Pro также поддерживает смешанную передачу, когда параметры передаются и по именам, и по позиции. В этом случае позиционные параметры должны идти перед параметрами, передаваемыми по именам.

Мы рассмотрим все три варианта записи на примере следующей функции:

    CREATE FUNCTION concat_lower_or_upper(a text, b text,
    uppercase boolean DEFAULT false)
    RETURNS text
    AS
    $$
    SELECT CASE
            WHEN $3 THEN UPPER($1 || ' ' || $2)
            ELSE LOWER($1 || ' ' || $2)
            END;
    $$
    LANGUAGE SQL IMMUTABLE STRICT;
Функция concat_lower_or_upper имеет два обязательных параметра: a и b. Кроме того, есть один необязательный параметр uppercase, который по умолчанию имеет значение false. Аргументы a и b будут сложены вместе и переведены в верхний или нижний регистр, в зависимости от параметра uppercase. Остальные тонкости реализации функции сейчас не важны (подробнее о них рассказано в Главе 36).

## 4.3.1. Позиционная передача

Позиционная передача — это традиционный механизм передачи аргументов функции в Postgres Pro. Пример такой записи:

    SELECT concat_lower_or_upper('Hello', 'World', true);
    concat_lower_or_upper 
    -----------------------
    HELLO WORLD
    (1 row)
Все аргументы указаны в заданном порядке. Результат возвращён в верхнем регистре, так как параметр uppercase имеет значение true. Ещё один пример:

    SELECT concat_lower_or_upper('Hello', 'World');
    concat_lower_or_upper 
    -----------------------
    hello world
    (1 row)
Здесь параметр uppercase опущен, и поэтому он принимает значение по умолчанию (false), и результат переводится в нижний регистр. В позиционной записи любые аргументы с определённым значением по умолчанию можно опускать справа налево.

## 4.3.2. Именная передача

При именной передаче для аргумента добавляется имя, которое отделяется от выражения значения знаками =>. Например:

    SELECT concat_lower_or_upper(a => 'Hello', b => 'World');
    concat_lower_or_upper 
    -----------------------
    hello world
    (1 row)
Здесь аргумент uppercase был так же опущен, так что он неявно получил значение false. Преимуществом такой записи является возможность записывать аргументы в любом порядке, например:

    SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true);
    concat_lower_or_upper 
    -----------------------
    HELLO WORLD
    (1 row)

    SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World');
    concat_lower_or_upper 
    -----------------------
    HELLO WORLD
    (1 row)
Для обратной совместимости поддерживается и старый синтаксис с ":=":

    SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World');
    concat_lower_or_upper 
    -----------------------
    HELLO WORLD
    (1 row)

## 4.3.3. Смешанная передача

При смешанной передаче параметры передаются и по именам, и по позиции. Однако, как уже было сказано, именованные аргументы не могут стоять перед позиционными. Например:

    SELECT concat_lower_or_upper('Hello', 'World', uppercase => true);
    concat_lower_or_upper 
    -----------------------
    HELLO WORLD
    (1 row)
В данном запросе аргументы a и b передаются по позиции, а uppercase — по имени. Единственное обоснование такого вызова здесь — он стал чуть более читаемым. Однако для более сложных функций с множеством аргументов, часть из которых имеют значения по умолчанию, именная или смешанная передача позволяют записать вызов эффективнее и уменьшить вероятность ошибок.

> Примечание
Именная и смешанная передача в настоящий момент не может использоваться при вызове агрегатной функции (но они допускаются, если агрегатная функция используется в качестве оконной).